import { v4 as uuidv4 } from 'uuid';
import path from 'path';
import { minioClient, minioConfig, getPublicUrl } from '../config/minio';
import type { Readable } from 'stream';

/**
 * MinIO 文件操作工具类
 */

export interface UploadResult {
  objectName: string;
  url: string;
  etag: string;
  size: number;
}

/**
 * 上传文件到 MinIO
 */
export async function uploadFile(
  file: Express.Multer.File | Buffer | Readable,
  originalName?: string,
  metadata?: Record<string, string>
): Promise<UploadResult> {
  try {
    // 生成唯一的对象名称
    const ext = originalName ? path.extname(originalName) : '';
    const objectName = `${Date.now()}-${uuidv4()}${ext}`;

    let fileBuffer: Buffer;
    let fileSize: number;
    let contentType: string;

    // 处理不同的文件类型
    if (Buffer.isBuffer(file)) {
      fileBuffer = file;
      fileSize = file.length;
      contentType = metadata?.['Content-Type'] || 'application/octet-stream';
    } else if ('buffer' in file) {
      // Express.Multer.File
      fileBuffer = file.buffer;
      fileSize = file.size;
      contentType = file.mimetype;
    } else {
      throw new Error('不支持的文件类型');
    }

    // 上传到 MinIO
    const uploadMetadata = {
      'Content-Type': contentType,
      'Original-Name': originalName || objectName,
      ...metadata,
    };

    const result = await minioClient.putObject(
      minioConfig.bucketName,
      objectName,
      fileBuffer,
      fileSize,
      uploadMetadata
    );

    return {
      objectName,
      url: getPublicUrl(objectName),
      etag: result.etag,
      size: fileSize,
    };
  } catch (error) {
    console.error('MinIO 上传文件失败:', error);
    throw new Error('文件上传失败');
  }
}

/**
 * 从 MinIO 下载文件
 */
export async function downloadFile(objectName: string): Promise<Readable> {
  try {
    const stream = await minioClient.getObject(minioConfig.bucketName, objectName);
    return stream;
  } catch (error) {
    console.error('MinIO 下载文件失败:', error);
    throw new Error('文件下载失败');
  }
}

/**
 * 删除 MinIO 中的文件
 */
export async function deleteFile(objectName: string): Promise<void> {
  try {
    await minioClient.removeObject(minioConfig.bucketName, objectName);
  } catch (error) {
    console.error('MinIO 删除文件失败:', error);
    throw new Error('文件删除失败');
  }
}

/**
 * 批量删除文件
 */
export async function deleteFiles(objectNames: string[]): Promise<void> {
  try {
    await minioClient.removeObjects(minioConfig.bucketName, objectNames);
  } catch (error) {
    console.error('MinIO 批量删除文件失败:', error);
    throw new Error('批量删除文件失败');
  }
}

/**
 * 获取文件信息
 */
export async function getFileStat(objectName: string) {
  try {
    const stat = await minioClient.statObject(minioConfig.bucketName, objectName);
    return stat;
  } catch (error) {
    console.error('MinIO 获取文件信息失败:', error);
    throw new Error('获取文件信息失败');
  }
}

/**
 * 生成预签名的下载 URL（用于私有文件）
 */
export async function getPresignedUrl(
  objectName: string,
  expirySeconds: number = 3600
): Promise<string> {
  try {
    const url = await minioClient.presignedGetObject(
      minioConfig.bucketName,
      objectName,
      expirySeconds
    );
    return url;
  } catch (error) {
    console.error('MinIO 生成预签名 URL 失败:', error);
    throw new Error('生成下载链接失败');
  }
}

/**
 * 列出桶中的文件
 */
export async function listFiles(prefix?: string, maxKeys: number = 1000): Promise<any[]> {
  try {
    const stream = minioClient.listObjectsV2(
      minioConfig.bucketName,
      prefix,
      true,
      ''
    );

    const objects: any[] = [];
    
    return new Promise((resolve, reject) => {
      stream.on('data', (obj) => {
        if (objects.length < maxKeys) {
          objects.push(obj);
        }
      });
      
      stream.on('end', () => {
        resolve(objects);
      });
      
      stream.on('error', (error) => {
        reject(error);
      });
    });
  } catch (error) {
    console.error('MinIO 列出文件失败:', error);
    throw new Error('列出文件失败');
  }
}

